﻿using System;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Drawing;

namespace BigPixels
{
    public enum SaveBehaviour
    {
        Save,
        SaveAs,
        ExportAs,
    }

    public partial class Form1 : Form
    {
        public ApplicationSettings Settings
        {
            get;
            private set;
        }

        public Sketch Sketch
        {
            get;
            private set;
        }

        public ToolsForm Tools
        {
            get;
            private set;
        }

        public Form1()
        {
            InitializeComponent();

            this.Settings = Program.Load();
            this.Sketch = new Sketch();

            this.Settings = Program.Load();

            NewDocument();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Tools = new ToolsForm();
            this.Tools.Owner = this;

			if (this.WindowState == FormWindowState.Normal)
			{
				// position tools window at top right...
				this.Tools.StartPosition = FormStartPosition.Manual;
				this.Tools.Location = new Point(this.Right + 20, this.Top);
			}
			else if (this.WindowState == FormWindowState.Maximized)
			{
				this.Tools.StartPosition = FormStartPosition.Manual;
				this.Tools.Location = new Point(this.Left, this.Top);
			}

            this.Tools.Show();

            this.canvas1.GridSize = this.Settings.GridSize;

            this.canvas1.PaintColour = this.Tools.PaintColour = Color.Black;
            this.canvas1.CanvasColour = this.Tools.CanvasColour = Color.White;

            this.Tools.PaintColourSelected += new EventHandler<ColourSelectEventArgs>(Tools_PaintColourSelected);
            this.Tools.CanvasColourSelected += new EventHandler<ColourSelectEventArgs>(Tools_CanvasColourSelected);
            this.canvas1.CanvasChanged += new EventHandler(canvas1_CanvasChanged);

			// Set the opacity so we can trace existing pics easily.
			if (this.Settings.Opacity > 0F && this.Settings.Opacity < 1F)
			{
				this.Opacity = this.Settings.Opacity;
			}
        }

        void Tools_PaintColourSelected(object sender, ColourSelectEventArgs e)
        {
            this.canvas1.PaintColour = e.Value;
        }

        void Tools_CanvasColourSelected(object sender, ColourSelectEventArgs e)
        {
            this.canvas1.CanvasColour = e.Value;
        }

        void canvas1_CanvasChanged(object sender, EventArgs e)
        {
            SetDirty(true);
        }

        private void SetDirty(bool flag)
        {
            this.Sketch.IsDirty = flag;
            ShowDocumentStatus(this.Sketch);
        }

        private void SetFilename(string filename)
        {
            this.Sketch.Path = filename;
            ShowDocumentStatus(this.Sketch);
        }

        private void mnuFileNew_Click(object sender, EventArgs e)
        {
            NewDocument();
        }

        private void mnuFileOpen_Click(object sender, EventArgs e)
        {
            OpenSketch(null);
        }

        private void mnuFileSave_Click(object sender, EventArgs e)
        {
            SaveSketch(SaveBehaviour.Save);
        }

        private void mnuFileSaveAs_Click(object sender, EventArgs e)
        {
            SaveSketch(SaveBehaviour.SaveAs);
        }
        
        private void mnuFileImportPalette_Click(object sender, EventArgs e)
        {
            // load palette from image...
            using (var dlg = new OpenFileDialog())
            {
                dlg.Filter = "All Supported Files (*.jpg, *.png, *.bmp)|*.jpg;*.png;*.bmp|All Files (*.*)|*.*";
                dlg.FilterIndex = 1;

                var result = dlg.ShowDialog(this);

                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    this.Cursor = Cursors.WaitCursor;

                    var path = dlg.FileName;

                    var newPalette = BigPixelStorage.LoadPaletteFromImage(path);

                    this.Tools.ImportColours(newPalette);

                    this.Cursor = Cursors.Default;
                }
            }
        }

        private void mnuFileExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!CloseDocument())
            {
                e.Cancel = true;
            }
            else
            {
                this.Tools.Close();
            }
        }

        private void mnuFileExport_Click(object sender, EventArgs e)
        {
            // save the bitmap...
            using (var dlg = new SaveFileDialog())
            {
                dlg.Filter = "Bitmap Image (*.bmp)|*.bmp|PNG Image (*.png)|*.png|Jpeg Image (*.jpg)|*.jpg|All Files (*.*)|*.*";

                var result = dlg.ShowDialog(this);

                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    var path = dlg.FileName;

                    //var saveWithGrid = MessageBox.Show("Export grid lines in image?", "Big Pixels", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                    this.canvas1.SaveToFile(path, 
                                            this.Settings, false);
                                            //saveWithGrid == DialogResult.Yes);
                }
            }
        }

        private bool NewDocument() 
        {
            if (!CloseDocument()) 
                return false;

            this.Sketch = new Sketch();
            ShowDocumentStatus(this.Sketch);

            SetDirty(false);
            ShowDocumentStatus(this.Sketch);

            return true;
        }

        private bool OpenSketch(string newFileName) 
        {
            // Check if we can close current file
            if (!CloseDocument()) 
                return false;

            // Get the file to open
            if (string.IsNullOrEmpty(newFileName)) 
            {
                using (var dlg = new OpenFileDialog())
                {
                    dlg.Filter = Sketch.FileFilter;

                    var result = dlg.ShowDialog(this);

                    if (result == System.Windows.Forms.DialogResult.OK)
                    {
                        this.Cursor = Cursors.WaitCursor;

                        var cells = this.Sketch.Load(dlg.FileName);

                        if (cells.Count > 0)
                        {
                            int side = (int)Math.Sqrt(cells.Count);

                            this.canvas1.GridSize = side;
                        }

                        int index = 0;

                        for (int x = 0; x < this.canvas1.Grid.GridSize.Width; ++x)
                        {
                            for (int y = 0; y < this.canvas1.Grid.GridSize.Height; ++y)
                            {
                                if (index < cells.Count)
                                {
                                    this.canvas1.Grid[x, y].Pixel = new PixelValue(cells[index++].Pixel.Value);
                                }
                                else
                                {
                                    this.canvas1.Grid[x, y].Pixel.Value = Color.Empty;
                                }
                            }
                        }

                        this.Cursor = Cursors.Default;
                    }
                }
            }

            SetDirty(false);
            ShowDocumentStatus(this.Sketch);

            return true;
        }

        private bool CloseDocument()
        {
            if (!this.Sketch.IsDirty) 
                return true;

            var result = MessageBox.Show(this, 
                                        "Save changes?",
                                        Application.ProductName,
                                        MessageBoxButtons.YesNoCancel);

            switch (result)
            {
                case DialogResult.Yes:
                    return SaveSketch(SaveBehaviour.Save);

                case DialogResult.No: 
                    return true;

                case DialogResult.Cancel: 
                    return false;

                default: 
                    return false;
            }
        }


        private void SaveSketch(string path)
        {
            var cells = new List<Cell>();

            for (int x = 0; x < this.canvas1.Grid.GridSize.Width; ++x)
            {
                for (int y = 0; y < this.canvas1.Grid.GridSize.Height; ++y)
                {
                    var cell = this.canvas1.Grid[x, y];
                    cells.Add(new Cell(cell.Position.X, cell.Position.Y, cell.Pixel.Value));
                }
            }

            this.Sketch.Save(path, cells);
        }

        private bool SaveSketch(SaveBehaviour behaviour)
        {
            string newFileName = this.Sketch.Path;
  
            if ((behaviour == SaveBehaviour.SaveAs) || string.IsNullOrEmpty(newFileName)) 
            {
                using (var dlg = new SaveFileDialog())
                {
                    dlg.Filter = Sketch.FileFilter;

                    if(!string.IsNullOrEmpty(newFileName))
                    {
                        dlg.InitialDirectory = Path.GetDirectoryName(newFileName);
                        dlg.FileName = Path.GetFileName(newFileName);
                    }
                    else 
                    {
                        dlg.FileName = "Untitled";
                    }

                    DialogResult result = dlg.ShowDialog(this);
    
                    if (result != DialogResult.OK) 
                        return false;
    
                    newFileName = dlg.FileName;
                }
            }

            SaveSketch(newFileName);
            SetDirty(false);
            ShowDocumentStatus(this.Sketch);

            return true;
        }

        private void ShowDocumentStatus(Sketch sketch)
        {
            this.Text = string.Format("{0} {1} - Big Pixels",
                                Path.GetFileNameWithoutExtension(sketch.Path),
                                sketch.IsDirty ? "*" : "");
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            this.canvas1.GridSize = this.Settings.GridSize = 32;
            this.canvas1.Invalidate();
            this.Invalidate();
            Program.Save(this.Settings);
        }

        private void menuItem3_Click(object sender, EventArgs e)
        {
            this.canvas1.GridSize = this.Settings.GridSize = 64;
            this.canvas1.Invalidate();
            this.Invalidate();
            Program.Save(this.Settings);
        }

        private void menuItem4_Click(object sender, EventArgs e)
        {
            this.canvas1.GridSize = this.Settings.GridSize = 16;
            this.canvas1.Invalidate();
            this.Invalidate();
            Program.Save(this.Settings);
        }

        void menuItem5_Click(object sender, System.EventArgs e)
        {
            // ask for custom size...
           // throw new System.NotImplementedException();
            var dlg = new CustomGridForm();

            dlg.GridSize = this.Settings.GridSize;

            if (dlg.ShowDialog () == System.Windows.Forms.DialogResult.OK)
            {
                this.canvas1.GridSize = this.Settings.GridSize = dlg.GridSize;
                this.canvas1.Invalidate();
                this.Invalidate();
                Program.Save(this.Settings);
            }
        }


    }
}
